home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / aminet / misc / sci / ephem_src_4_28.lha / plot.c < prev    next >
C/C++ Source or Header  |  1992-04-17  |  11KB  |  442 lines

  1. /* code to support the plotting capabilities.
  2.  * idea is to let the operator name a plot file and mark some fields for
  3.  * logging. then after each screen update, the logged fields are written to
  4.  * the plot file. later, the file may be plotted (very simplistically by 
  5.  * ephem, for now anyway, or by some other program entirely.).
  6.  * 
  7.  * format of the plot file is one line per coordinate: label,x,y
  8.  * if z was specified, it is a fourth field.
  9.  * x,y,z are plotted using %g format.
  10.  */
  11.  
  12. #include <stdio.h>
  13. #include <math.h>
  14. #include "screen.h"
  15.  
  16. extern char *strcpy();
  17.  
  18. #ifdef VMS
  19. #include <perror.h>
  20. #include <errno.h>
  21. #else
  22. extern char *sys_errlist[];
  23. extern errno;
  24. #endif
  25.  
  26. #define    errsys    (sys_errlist[errno])
  27.  
  28.  
  29. #define    TRACE(x)    {FILE *fp = fopen("trace","a"); fprintf x; fclose(fp);}
  30.  
  31. #define    MAXPLTLINES    10    /* max number of labeled lines we can track.
  32.                  * note we can't store more than NFLOGS fields
  33.                  * anyway (see flog.c).
  34.                  */
  35. #define    FNLEN        (14+1)    /* longest filename; plus 1 for \0 */
  36.  
  37. static char plt_filename[FNLEN] = "ephem.plt";    /* default plot file name */
  38. static FILE *plt_fp;        /* the plot file; == 0 means don't plot */
  39.  
  40. /* store the label and rcfpack()s for each line to track. */
  41. typedef struct {
  42.     char pl_label;
  43.     int pl_rcpx, pl_rcpy, pl_rcpz;
  44. } PltLine;
  45. static PltLine pltlines[MAXPLTLINES];
  46. static int npltlines;        /* number of pltlines[] in actual use */
  47.  
  48. static int plt_in_polar;    /*if true plot in polar coords, else cartesian*/
  49. static int pltsrchfld;        /* set when the Search field is to be plotted */
  50.  
  51. /* picked the Plot label:
  52.  * if on, just turn it off.
  53.  * if off, turn on, define fields or select name of file to plot and do it.
  54.  * TODO: more flexibility, more relevance.
  55.  */
  56. plot_setup()
  57. {
  58.     if (plt_fp)
  59.         plt_turn_off();
  60.     else {
  61.         static char *chcs[4] = {
  62.         "Select fields", "Display a plot file", (char *)0,
  63.         "Begin plotting"
  64.         };
  65.         static int fn;    /* start with 0, then remember for next time */
  66.     ask:
  67.         chcs[2] = plt_in_polar ? "Polar coords" : "Cartesian coords";
  68.         switch (popup(chcs, fn, npltlines > 0 ? 4 : 3)) {
  69.         case 0: fn = 0; plt_select_fields(); goto ask;
  70.         case 1: fn = 1; plt_file(); goto ask;
  71.         case 2: fn = 2; plt_in_polar ^= 1; goto ask;
  72.         case 3: fn = 3; plt_turn_on(); break;
  73.         default: break;
  74.         }
  75.     }
  76. }
  77.  
  78. /* write the active plotfields to the current plot file, if one is open. */
  79. plot()
  80. {
  81.     if (plt_fp) {
  82.         PltLine *plp;
  83.         double x, y, z;
  84.         if (!srch_ison() && pltsrchfld) {
  85.         /* if searching is not on but we are plotting the search
  86.          * funtion we must evaluate and log it ourselves here and now.
  87.          * plt_turn_on() insured there is a good function to eval.
  88.          * N.B. if searching IS on, we rely on main() having called
  89.          * srch_eval() BEFORE plot() so it is already evaluated.
  90.          */
  91.         double e;
  92.         char errmsg[128];
  93.         if (execute_expr (&e, errmsg) < 0) {
  94.             f_msg (errmsg);
  95.             plt_turn_off();
  96.             return;
  97.         } else
  98.             (void) flog_log (R_SRCH, C_SRCH, e, "");
  99.         }
  100.         /* plot in order of original selection */
  101.         for (plp = pltlines; plp < &pltlines[npltlines]; plp++) {
  102.         if (flog_get (plp->pl_rcpx, &x, (char *)0) == 0 
  103.             && flog_get (plp->pl_rcpy, &y, (char *)0) == 0) {
  104.             (void) fprintf (plt_fp, "%c,%.12g,%.12g", plp->pl_label,
  105.                                     x, y);
  106.             if (flog_get (plp->pl_rcpz, &z, (char *)0) == 0)
  107.             (void) fprintf (plt_fp, ",%.12g", z);
  108.             (void) fprintf (plt_fp, "\n");
  109.         }
  110.         }
  111.     }
  112. }
  113.  
  114. plot_prstate (force)
  115. int force;
  116. {
  117.     static last;
  118.     int this = plt_fp != 0;
  119.  
  120.     if (force || this != last) {
  121.         f_string (R_PLOT, C_PLOTV, this ? " on" : "off");
  122.         last = this;
  123.     }
  124. }
  125.  
  126. plot_ison()
  127. {
  128.     return (plt_fp != 0);
  129. }
  130.  
  131. static
  132. plt_reset()
  133. {
  134.     PltLine *plp;
  135.  
  136.     for (plp = &pltlines[npltlines]; --plp >= pltlines; ) {
  137.         (void) flog_delete (plp->pl_rcpx);
  138.         (void) flog_delete (plp->pl_rcpy);
  139.         (void) flog_delete (plp->pl_rcpz);
  140.         plp->pl_rcpx = plp->pl_rcpy = plp->pl_rcpz = 0;
  141.     }
  142.     npltlines = 0;
  143.     pltsrchfld = 0;
  144. }
  145.  
  146. /* let operator select the fields he wants to plot.
  147.  * register them with flog and keep rcfpack() in pltlines[] array.
  148.  * as a special case, set pltsrchfld if Search field is selected.
  149.  */
  150. static
  151. plt_select_fields()
  152. {
  153.     static char hlp[] = "move and RETURN to select a field, or q to quit";
  154.     static char sry[] = "Sorry; can not log any more fields.";
  155.     int f = rcfpack(R_UT,C_UTV,0); /* TODO: start where main was? */
  156.     int sf = rcfpack (R_SRCH, C_SRCH, 0);
  157.     char buf[64];
  158.     int i;
  159.     int tmpf;
  160.  
  161.     plt_reset();
  162.     for (i = 0; i < MAXPLTLINES; i++) {
  163.         (void) sprintf (buf, "select x field for line %d", i+1);
  164.         f = sel_fld (f, alt_menumask()|F_PLT, buf, hlp);
  165.         if (!f)
  166.         break;
  167.         if (flog_add (f) < 0) {
  168.         f_msg (sry);
  169.         break;
  170.         }
  171.         pltlines[i].pl_rcpx = f;
  172.         if (f == sf)
  173.         pltsrchfld = 1;
  174.  
  175.         (void) sprintf (buf, "select y field for line %d", i+1);
  176.         f = sel_fld (f, alt_menumask()|F_PLT, buf, hlp);
  177.         if (!f) {
  178.         (void) flog_delete (pltlines[i].pl_rcpx);
  179.         break;
  180.         }
  181.         if (flog_add (f) < 0) {
  182.         (void) flog_delete (pltlines[i].pl_rcpx);
  183.         f_msg (sry);
  184.         break;
  185.         }
  186.         pltlines[i].pl_rcpy = f;
  187.         if (f == sf)
  188.         pltsrchfld = 1;
  189.  
  190.         (void) sprintf (buf, "select z field for line %d (q for no z)",i+1);
  191.         tmpf = sel_fld (f, alt_menumask()|F_PLT, buf, hlp);
  192.         if (tmpf) {
  193.         if (flog_add (tmpf) < 0) {
  194.             (void) flog_delete (pltlines[i].pl_rcpx);
  195.             (void) flog_delete (pltlines[i].pl_rcpy);
  196.             f_msg (sry);
  197.             break;
  198.         }
  199.         pltlines[i].pl_rcpz = tmpf;
  200.         if (tmpf == sf)
  201.             pltsrchfld = 1;
  202.         f = tmpf;
  203.         }
  204.  
  205.         do {
  206.         (void) sprintf(buf,"enter a one-character label for line %d: ",
  207.                                     i+1);
  208.         f_prompt (buf);
  209.         } while (read_line (buf, 1) != 1);
  210.         pltlines[i].pl_label = *buf;
  211.     }
  212.     npltlines = i;
  213. }
  214.  
  215. static
  216. plt_turn_off ()
  217. {
  218.     (void) fclose (plt_fp);
  219.     plt_fp = 0;
  220.     plot_prstate(0);
  221. }
  222.  
  223. /* turn on plotting.
  224.  * establish a file to use (and thereby set plt_fp, the plotting_is_on flag).
  225.  * also check that there is a srch function if it is being plotted.
  226.  */
  227. static
  228. plt_turn_on ()
  229. {
  230.     int sf = rcfpack(R_SRCH, C_SRCH, 0);
  231.     char fn[FNLEN], fnq[NC];
  232.     char *optype;
  233.     int n;
  234.     PltLine *plp;
  235.  
  236.     /* insure there is a valid srch function if we are to plot it */
  237.     for (plp = &pltlines[npltlines]; --plp >= pltlines; )
  238.         if ((plp->pl_rcpx == sf || plp->pl_rcpy == sf || plp->pl_rcpz == sf)
  239.             && !prog_isgood()) {
  240.         f_msg ("Plotting search function but it is not defined.");
  241.         return;
  242.         }
  243.  
  244.     /* prompt for file name, giving current as default */
  245.     (void) sprintf (fnq, "file to write <%s>: ", plt_filename);
  246.     f_prompt (fnq);
  247.     n = read_line (fn, sizeof(fn)-1);
  248.  
  249.     /* leave plotting off if type END.
  250.      * reuse same fn if just type \n
  251.      */
  252.     if (n < 0)
  253.         return;
  254.     if (n > 0)
  255.         (void) strcpy (plt_filename, fn);
  256.  
  257.     /* give option to append if file already exists */
  258.     optype = "w";
  259.     if (access (plt_filename, 2) == 0) {
  260.         while (1) {
  261.         f_prompt ("files exists; append or overwrite (a/o)?: ");
  262.         n = read_char();
  263.         if (n == 'a') {
  264.             optype = "a";
  265.             break;
  266.         }
  267.         if (n == 'o')
  268.             break;
  269.         }
  270.     }
  271.  
  272.     /* plotting is on if file opens ok */
  273.     plt_fp = fopen (plt_filename, optype);
  274.     if (!plt_fp) {
  275.         char buf[NC];
  276.         (void) sprintf (buf, "can not open %s: %s", plt_filename, errsys);
  277.         f_prompt (buf);
  278.         (void)read_char();
  279.     } else {
  280.         /* add a title if desired */
  281.         static char tp[] = "Title (q to skip): ";
  282.         f_prompt (tp);
  283.         if (read_line (fnq, PW - sizeof(tp)) > 0)
  284.         (void) fprintf (plt_fp, "* %s\n", fnq);
  285.     }
  286.     plot_prstate (0);
  287. }
  288.  
  289. /* ask operator for a file to plot. if it's ok, do it.
  290.  */
  291. static
  292. plt_file ()
  293. {
  294.     char fn[FNLEN], fnq[64];
  295.     FILE *pfp;
  296.     int n;
  297.  
  298.     /* prompt for file name, giving current as default */
  299.     (void) sprintf (fnq, "file to read <%s>: ", plt_filename);
  300.     f_prompt (fnq);
  301.     n = read_line (fn, sizeof(fn)-1);
  302.  
  303.     /* forget it if type END.
  304.      * reuse same fn if just type \n
  305.      */
  306.     if (n < 0)
  307.         return;
  308.     if (n > 0)
  309.         (void) strcpy (plt_filename, fn);
  310.  
  311.     /* do the plot if file opens ok */
  312.     pfp = fopen (plt_filename, "r");
  313.     if (pfp) {
  314.         if (plt_in_polar)
  315.         plot_polar (pfp);
  316.         else
  317.         plot_cartesian (pfp);
  318.         (void) fclose (pfp);
  319.     } else {
  320.         char buf[NC];
  321.         (void) sprintf (buf, "can not open %s: %s", plt_filename, errsys);
  322.         f_prompt (buf);
  323.         (void)read_char();
  324.     }
  325. }
  326.  
  327. /* plot the given file on the screen in cartesian coords.
  328.  * TODO: add z tags somehow
  329.  * N.B. do whatever you like but redraw the screen when done.
  330.  */
  331. static
  332. plot_cartesian (pfp)
  333. FILE *pfp;
  334. {
  335.     static char fmt[] = "%c,%lf,%lf";
  336.     double x, y;    /* N.B. be sure these match what scanf's %lf wants*/
  337.     double minx, maxx, miny, maxy;
  338.     char buf[128];
  339.     int npts = 0;
  340.     char c;
  341.  
  342.     /* find ranges and number of points */
  343.     while (fgets (buf, sizeof(buf), pfp)) {
  344.         if (sscanf (buf, fmt, &c, &x, &y) != 3)
  345.         continue;
  346.         if (npts++ == 0) {
  347.         maxx = minx = x;
  348.         maxy = miny = y;
  349.         } else {
  350.         if (x > maxx) maxx = x;
  351.         else if (x < minx) minx = x;
  352.         if (y > maxy) maxy = y;
  353.         else if (y < miny) miny = y;
  354.         }
  355.     }
  356.  
  357. #define    SMALL    (1e-10)
  358.     if (npts < 2 || fabs(minx-maxx) < SMALL || fabs(miny-maxy) < SMALL)
  359.         f_prompt ("At least two different points required to plot.");
  360.     else {
  361.         /* read file again, this time plotting */
  362.         rewind (pfp);
  363.         c_erase();
  364.         while (fgets (buf, sizeof(buf), pfp)) {
  365.         int row, col;
  366.         if (sscanf (buf, fmt, &c, &x, &y) != 3)
  367.             continue;
  368.         row = NR-(int)((NR-1)*(y-miny)/(maxy-miny)+0.5);
  369.         col =  1+(int)((NC-1)*(x-minx)/(maxx-minx)+0.5);
  370.         if (row == NR && col == NC)
  371.             col--;    /* avoid lower right scrolling corner */
  372.         f_char (row, col, c);
  373.         }
  374.  
  375.         /* label axes */
  376.         f_double (1, 1, "%g", maxy);
  377.         f_double (NR-1, 1, "%g", miny);
  378.         f_double (NR, 1, "%g", minx);
  379.         f_double (NR, NC-10, "%g", maxx);
  380.     }
  381.  
  382.     /* hit any key to resume... */
  383.     (void) read_char();
  384.     redraw_screen (2);    /* full redraw */
  385. }
  386.  
  387. /* plot the given file on the screen in polar coords.
  388.  * first numberic field in plot file is r, second is theta in degrees.
  389.  * TODO: add z tags somehow
  390.  * N.B. do whatever you like but redraw the screen when done.
  391.  */
  392. static
  393. plot_polar (pfp)
  394. FILE *pfp;
  395. {
  396.     static char fmt[] = "%c,%lf,%lf";
  397.     double r, th;    /* N.B. be sure these match what scanf's %lf wants*/
  398.     double maxr;
  399.     char buf[128];
  400.     int npts = 0;
  401.     char c;
  402.  
  403.     /* find ranges and number of points */
  404.     while (fgets (buf, sizeof(buf), pfp)) {
  405.         if (sscanf (buf, fmt, &c, &r, &th) != 3)
  406.         continue;
  407.         if (npts++ == 0)
  408.         maxr = r;
  409.         else
  410.         if (r > maxr)
  411.             maxr = r;
  412.     }
  413.  
  414.     if (npts < 2)
  415.         f_prompt ("At least two points required to plot.");
  416.     else {
  417.         /* read file again, this time plotting */
  418.         rewind (pfp);
  419.         c_erase();
  420.         while (fgets (buf, sizeof(buf), pfp)) {
  421.         int row, col;
  422.         double x, y;
  423.         if (sscanf (buf, fmt, &c, &r, &th) != 3)
  424.             continue;
  425.         x = r * cos(th/57.2958);    /* degs to rads */
  426.         y = r * sin(th/57.2958);
  427.         row = NR-(int)((NR-1)*(y+maxr)/(2.0*maxr)+0.5);
  428.         col =  1+(int)((NC-1)*(x+maxr)/(2.0*maxr)/ASPECT+0.5);
  429.         if (row == NR && col == NC)
  430.             col--;    /* avoid lower right scrolling corner */
  431.         f_char (row, col, c);
  432.         }
  433.  
  434.         /* label radius */
  435.         f_double (NR/2, NC-10, "%g", maxr);
  436.     }
  437.  
  438.     /* hit any key to resume... */
  439.     (void) read_char();
  440.     redraw_screen (2);    /* full redraw */
  441. }
  442.